package com.gzsxy.esjy.feign;

import com.alibaba.fastjson.JSON;
import org.springframework.cloud.openfeign.FeignClient;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import feign.FeignException;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 基础熔断降级处理工厂
 * @date 2021/10/14 14:22
 */
@Slf4j
@Component
public class BaseFallbackFactory<T> implements FallbackFactory<T> {


    protected final String serviceName;

    protected final static String ERROR = "服务[%s]%s";

    protected static Map<String, String> map;


    public BaseFallbackFactory() {
        super();
        this.serviceName = getServiceName();
    }

    //获取服务名的中文字符串
    static {
        PathMatchingResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();

        try {
            Resource[] resources = resourceLoader.getResources("classpath*:server-name.json");
            for (Resource resource : resources) {
                if (map == null) {
                    map = JSON.parseObject(resource.getInputStream(), Map.class);
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }

    }


    //获取服务名
    private final String getServiceName() {
        //getGenericSuperclass()获得带有泛型的父类     BaseFallbackFactory<T>
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            // 强制转化“参数化类型”
            ParameterizedType parameterizedType = (ParameterizedType) type;
            //getActualTypeArguments获取参数化类型的数组，泛型可能有多个
            Type[] types = parameterizedType.getActualTypeArguments();
            Class<T> clazz = (Class<T>) types[0];
            //获取当前泛型类上的FeignClient注解
            FeignClient feign = clazz.getAnnotation(FeignClient.class);
            //获取注解中value属性值  （服务名）  @feignClient（value=”core-server“）
            String value = feign.value();
            String s = map.get(value);
            if (StringUtils.isNotBlank(s)) {
                return s;
            }
            return value;
        }
        return null;
    }

    /**
     * @param
     * @return
     * @description: 默认异常处理，可覆盖
     */
    @Override
    public T create(Throwable ex) {
        System.out.println("进入异常处理");
        System.out.println(ex.getMessage());
        if (ex instanceof FeignException) {
            String message = ex.getMessage();
            NormalResponse response = null;
            System.out.println("进入FeignException");
            if (message != null) {
                String[] msg = message.split("content:\n");
                if (msg.length > 0) {
                    message = msg[0];
                }
                if (msg.length > 1) {
                    response = JSON.parseObject(msg[1], NormalResponse.class);
                    if (response != null) {
                        String message1 = response.getMessage();
                        log.error(String.format(ERROR, serviceName, "内部异常"), ex);

                        throw new IllegalArgumentException(message1);
                    }
                }
            }
            throw new IllegalArgumentException(message);
        }
        if (ex instanceof HystrixTimeoutException) {
            throw new IllegalArgumentException(String.format(ERROR, serviceName, "执行超时"));
        }
        if (ex.getMessage().contains("Load balancer does not have available server for client")) {
            throw new IllegalArgumentException(String.format(ERROR, serviceName, "未启动"));
        }
        throw new IllegalArgumentException(String.format(ERROR, serviceName, "未知异常"));
    }
}
